#!/bin/bash
{
	#////////////////////////////////////
	# DietPi-VPN
	#
	#////////////////////////////////////
	# Created by Daniel Knight / daniel.knight@dietpi.com / dietpi.com
	# Updated by MichaIng / micha@dietpi.com / dietpi.com
	# Reworked by ravenclaw900 / https://github.com/ravenclaw900
	#
	#////////////////////////////////////
	#
	# Info:
	# - Location: /boot/dietpi/dietpi-vpn
	# - GUI to setup a VPN client connection
	# - Allows to automatically connect on boot
	# - Allows to enable a killswitch
	# - Allows to add custom post-up and pre-down scripts
	readonly USAGE='
Usage: dietpi-vpn [<command>]
Available commands:
  <empty>		Interactive menu to control VPN settings and connection
  status		Print VPN connection status
'	#////////////////////////////////////

	# Grab input
	readonly INPUT=$1

	# Import DietPi-Globals --------------------------------------------------------------
	# - Only load for interactive menu
	if [[ $INPUT ]]
	then
		readonly G_PROGRAM_NAME='DietPi-VPN'
	else
		. /boot/dietpi/func/dietpi-globals
		readonly G_PROGRAM_NAME='DietPi-VPN'
		G_CHECK_ROOT_USER
		G_CHECK_ROOTFS_RW
		G_INIT
	fi
	# Import DietPi-Globals --------------------------------------------------------------

	readonly FP_SETTINGS='/var/lib/dietpi/dietpi-vpn'
	readonly FP_SETTINGS_DIETPI="$FP_SETTINGS/settings_dietpi.conf"
	readonly FP_SETTINGS_OVPN="$FP_SETTINGS/settings_ovpn.conf"
	readonly FP_CUSTOM_UP="$FP_SETTINGS/up.sh"
	readonly FP_CUSTOM_DOWN="$FP_SETTINGS/down.sh"
	readonly FP_STATIC_UP="$FP_SETTINGS/static_up.sh"
	readonly FP_STATIC_DOWN="$FP_SETTINGS/static_down.sh"
	readonly FP_NORDVPN='/etc/openvpn/nordvpn'
	readonly FP_PROTONVPN='/etc/openvpn/protonvpn'
	readonly FP_PROTONVPN_SERVERS="$FP_PROTONVPN/serverlist.txt"
	readonly FP_PROTONVPN_TEMPLATE="$FP_PROTONVPN/template.ovpn"
	readonly FP_IPVANISH='/etc/openvpn/ipvanish'
	readonly FP_PIA='/etc/openvpn/pia'
	readonly FP_CLIENT_OVPN='/etc/openvpn/client.ovpn'
	readonly IFACE='tun0'
	readonly CONNECTION_TIMEOUT=20 # seconds

	VPN_PROVIDER=
	VPN_USERNAME=
	VPN_PASSWORD=
	VPN_SERVER=
	PROTOCOL='udp'
	VPN_PORT=1194
	VPN_CONNECTED=0
	WAN_IP=
	RX='N/A'
	TX='N/A'

	Update_WAN_IP(){ WAN_IP=$(curl -sSfLm 3 https://freegeoip.app/csv/ 2>&1 | mawk -F, '($5){r=$5" "}{print $1" "r$3}'); }

	Check_Connected()
	{
		[[ $(ip r l dev $IFACE 2> /dev/null) ]] && VPN_CONNECTED=1 || VPN_CONNECTED=0
		return $(( ! $VPN_CONNECTED ))
	}

	Get_Connection_Info()
	{
		RX='N/A'
		if [[ -f /sys/class/net/$IFACE/statistics/rx_bytes ]]
		then
			local rx=$(</sys/class/net/$IFACE/statistics/rx_bytes)
			[[ $rx =~ ^[0-9]+$ ]] && RX="$(( $rx / 1024**2 )) MiB"
		fi
		TX='N/A'
		if [[ -f /sys/class/net/$IFACE/statistics/tx_bytes ]]
		then
			local tx=$(</sys/class/net/$IFACE/statistics/tx_bytes)
			[[ $tx =~ ^[0-9]+$ ]] && TX="$(( $tx / 1024**2 )) MiB"
		fi
	}

	# $1 == -f: Force update, remove current server list/configs when existent
	Update_Servers()
	{
		if [[ $VPN_PROVIDER == 'NordVPN' ]]
		then
			[[ $1 != '-f' && -d $FP_NORDVPN ]] && return 0
			[[ $1 != '-f' ]] || G_WHIP_YESNO 'This will remove all NordVPN server files and perform a fresh download of NordVPN server configurations. Once completed, you will need to reselect a NordVPN server from the new list.\n\nDo you want to continue?' || return 0
			G_EXEC curl -sSfLO 'https://downloads.nordcdn.com/configs/archives/servers/ovpn.zip'
			VPN_SERVER=
			[[ -d $FP_NORDVPN ]] && G_EXEC_DESC='Removing old NordVPN server configs' G_EXEC rm -R $FP_NORDVPN
			G_EXEC mkdir -p $FP_NORDVPN
			G_EXEC unzip -o ovpn.zip -d $FP_NORDVPN
			G_EXEC_NOEXIT=1 G_EXEC rm ovpn.zip

		elif [[ $VPN_PROVIDER == 'ProtonVPN' ]]
		then
			[[ $1 != '-f' && -d $FP_PROTONVPN ]] && return 0
			[[ $1 != '-f' ]] || G_WHIP_YESNO 'This will remove all ProtonVPN server files and perform a fresh download of the ProtonVPN server list. Once completed, you will need to reselect a ProtonVPN server from the new list.\n\nDo you want to continue?' || return 0
			G_EXEC curl -sSfLO 'https://api.protonvpn.ch/vpn/logicals'
			VPN_SERVER=
			[[ -d $FP_PROTONVPN ]] && G_EXEC_DESC='Removing old ProtonVPN server configs' G_EXEC rm -R $FP_PROTONVPN
			G_EXEC mkdir -p $FP_PROTONVPN
			sed 's/"Domain":"/\n/g' logicals | mawk -F\" 'NR % 2 == 0 {print $1}' > $FP_PROTONVPN_SERVERS
			G_EXEC_NOEXIT=1 G_EXEC rm logicals

			# Download .ovpn file template
			G_EXEC curl -sSfL "https://raw.githubusercontent.com/$G_GITOWNER/DietPi/$G_GITBRANCH/.conf/dpv/protonvpn.template" -o $FP_PROTONVPN_TEMPLATE

		elif [[ $VPN_PROVIDER == 'IPVanish' ]]
		then
			[[ $1 != '-f' && -d $FP_IPVANISH ]] && return 0
			[[ $1 != '-f' ]] || G_WHIP_YESNO 'This will remove all IPVanish server files and perform a fresh download of IPVanish server configurations. Once completed, you will need to reselect a IPVanish server from the new list.\n\nDo you want to continue?' || return 0
			G_EXEC curl -sSfLO 'https://www.ipvanish.com/software/configs/configs.zip'
			VPN_SERVER=
			[[ -d $FP_IPVANISH ]] && G_EXEC_DESC='Removing old IPVanish server configs' G_EXEC rm -R $FP_IPVANISH
			G_EXEC mkdir -p $FP_IPVANISH
			G_EXEC unzip -o configs.zip -d $FP_IPVANISH
			G_EXEC_NOEXIT=1 G_EXEC rm configs.zip || :

		elif [[ $VPN_PROVIDER == 'PIA' ]]
		then
			[[ $1 != '-f' && -d $FP_PIA ]] && return 0
			[[ $1 != '-f' ]] || G_WHIP_YESNO 'This will remove all PIA server files and perform a fresh download of PIA server configurations. Once completed, you will need to reselect a PIA server from the new list.\n\nDo you want to continue?' || return 0
			G_EXEC curl -sSfLO 'https://www.privateinternetaccess.com/openvpn/openvpn-strong.zip'
			VPN_SERVER=
			[[ -d $FP_PIA ]] && G_EXEC_DESC='Removing old PIA server configs' G_EXEC rm -R $FP_PIA
			G_EXEC mkdir -p $FP_PIA
			G_EXEC unzip -o openvpn-strong.zip -d $FP_PIA
			G_EXEC_NOEXIT=1 G_EXEC rm openvpn-strong.zip || :

		elif [[ $VPN_PROVIDER == 'Custom' ]]
		then
			G_WHIP_MSG "Please select your custom .ovpn client config file from the next file browser dialogue. It will be copied to $FP_CLIENT_OVPN and loaded from there."
			/boot/dietpi/dietpi-explorer 1 /etc/openvpn || return 1
			G_EXEC umask 0077
			G_EXEC cp "$(</tmp/.dietpi-explorer_selected_location)" $FP_CLIENT_OVPN
			G_EXEC umask 0022
			G_EXEC_NOEXIT=1 G_EXEC rm /tmp/.dietpi-explorer_selected_location
			# Parse server IP/domain, port and protocol from client config, required for killswitch
			VPN_SERVER=$(mawk '$1=="remote" {print $2;exit}' $FP_CLIENT_OVPN)
			# - Port can be 2nd argument of "remote" option or dedicated "port" option, else defaults to "1194".
			VPN_PORT=$(mawk '$1=="remote" {print $3;exit}' $FP_CLIENT_OVPN)
			[[ $VPN_PORT =~ ^[0-9]+$ ]] || VPN_PORT=$(mawk '$1=="port" {print $2;exit}' $FP_CLIENT_OVPN)
			[[ $VPN_PORT =~ ^[0-9]+$ ]] || VPN_PORT=1194
			# - Protocol can be 3rd argument of "remote" option (when port is given) or 2nd argument of "remote" option (when port is not given) or dedicated "proto" option, else defaults to "udp".
			PROTOCOL=$(mawk '$1=="remote" {print $4;exit}' $FP_CLIENT_OVPN)
			[[ $PROTOCOL == 'udp' || $PROTOCOL == 'tcp' ]] || PROTOCOL=$(mawk '$1=="remote" {print $3;exit}' $FP_CLIENT_OVPN)
			# - When given via "proto" option, it is prefixed with "-client" (or "-server").
			[[ $PROTOCOL == 'udp' || $PROTOCOL == 'tcp' ]] || { PROTOCOL=$(mawk '$1=="proto" {print $2;exit}' $FP_CLIENT_OVPN); PROTOCOL=${PROTOCOL%-*}; }
			[[ $PROTOCOL == 'udp' || $PROTOCOL == 'tcp' ]] || PROTOCOL='udp'
		fi
	}

	Read_Settings(){ [[ -f $FP_SETTINGS_DIETPI ]] && . $FP_SETTINGS_DIETPI; }

	Save_Settings()
	{
		if ! [[ $VPN_SERVER && $VPN_USERNAME && $VPN_PASSWORD ]]
		then
			G_WHIP_MSG '[FAILED] You need to enter your VPN username + password and select a server, before settings can be applied.'
			return 1
		fi

		# Create static up/down scripts to disable IPv6 and apply killswitch if selected
		grep -q 'CONFIG_ENABLE_IPV6=1' /boot/dietpi.txt && G_WHIP_MSG 'Note that IPv6 will be disabled when VPN is connected, to prevent IPv6 leakage.'
		cat << _EOF_ > $FP_STATIC_UP
#!/bin/bash
# Disable IPv6 on connect to prevent IPv6 leakage
sysctl -w net.ipv6.conf.all.disable_ipv6=1
sysctl -w net.ipv6.conf.default.disable_ipv6=1
# If enabled, turn on killswitch
if [[ -f $FP_SETTINGS/killswitch.rules ]]
then
	iptables-save > $FP_SETTINGS/iptables.bak
	. $FP_SETTINGS_DIETPI
	VPN_SERVER=\$(mawk '\$1=="remote" {print \$2;exit}' $FP_CLIENT_OVPN)
	export VPN_SERVER PROTOCOL VPN_PORT
	iptables-restore < <(envsubst < $FP_SETTINGS/killswitch.rules)
fi
_EOF_
		cat << _EOF_ > $FP_STATIC_DOWN
#!/bin/dash
# If enabled, turn off killswitch
if [ -f $FP_SETTINGS/killswitch.rules ]
then
	iptables-restore < $FP_SETTINGS/iptables.bak
	rm $FP_SETTINGS/iptables.bak
fi
# Re-enables IPv6 on disconnect
if grep -q 'CONFIG_ENABLE_IPV6=1' /boot/dietpi.txt
then
	sysctl -w net.ipv6.conf.all.disable_ipv6=0
	sysctl -w net.ipv6.conf.default.disable_ipv6=0
fi
_EOF_
		G_EXEC chmod +x $FP_STATIC_UP $FP_STATIC_DOWN

		# Assure files are generated with strict modes right form the start
		G_EXEC umask 0077

		G_DIETPI-NOTIFY 2 'Generating OVPN file, please wait...'
		if [[ $VPN_PROVIDER == 'ProtonVPN' ]]
		then
			VPN_PORT=1194
			export PROTOCOL VPN_SERVER
			G_EXEC eval "envsubst < $FP_PROTONVPN_TEMPLATE > $FP_CLIENT_OVPN"

		elif [[ $VPN_PROVIDER == 'NordVPN' ]]
		then
			VPN_PORT=1194
			G_EXEC cp -f "$FP_NORDVPN/ovpn_$PROTOCOL/$VPN_SERVER" $FP_CLIENT_OVPN

		elif [[ $VPN_PROVIDER == 'IPVanish' ]]
		then
			VPN_PORT=1194
			G_EXEC cp -f "$FP_IPVANISH/$VPN_SERVER" $FP_CLIENT_OVPN
			# Fix CA path, as it is in subdirectory now
			G_CONFIG_INJECT 'ca[[:blank:]]' "ca $FP_IPVANISH/ca.ipvanish.com.crt" $FP_CLIENT_OVPN
			# Set protocol and port: UDP port 443 is default, but TCP 1194 and UDP 1194 are supported as well.
			G_CONFIG_INJECT 'proto[[:blank:]]' "proto $PROTOCOL" $FP_CLIENT_OVPN
			G_EXEC sed -i '/^[[:blank:]]*remote[[:blank:]]/s/[[:blank:]][0-9][0-9]*$/ 1194/' $FP_CLIENT_OVPN

		elif [[ $VPN_PROVIDER == 'PIA' ]]
		then
			G_EXEC cp -f "$FP_PIA/$VPN_SERVER" $FP_CLIENT_OVPN
			# Set protocol and port: UDP on 1197 is default but TCP on 501 is supported as well.
			G_CONFIG_INJECT 'proto[[:blank:]]' "proto $PROTOCOL" $FP_CLIENT_OVPN
			[[ $PROTOCOL == 'udp' ]] && VPN_PORT=1197 || VPN_PORT=501
			G_EXEC sed -i "/^[[:blank:]]*remote[[:blank:]]/s/[[:blank:]][0-9][0-9]*\$/ $VPN_PORT/" $FP_CLIENT_OVPN
		fi

		cat << _EOF_ > $FP_SETTINGS_OVPN
${VPN_USERNAME//\'/\'\\\'\'}
${VPN_PASSWORD//\'/\'\\\'\'}
_EOF_
		cat << _EOF_ > $FP_SETTINGS_DIETPI
VPN_PROVIDER='$VPN_PROVIDER'
VPN_USERNAME='${VPN_USERNAME//\'/\'\\\'\'}'
VPN_PASSWORD='${VPN_PASSWORD//\'/\'\\\'\'}'
VPN_SERVER='$VPN_SERVER'
PROTOCOL='$PROTOCOL'
VPN_PORT='$VPN_PORT'
_EOF_
		G_EXEC umask 0022
		G_EXEC chmod 0600 $FP_SETTINGS_OVPN $FP_SETTINGS_DIETPI $FP_CLIENT_OVPN
		G_EXEC chown root:root $FP_SETTINGS_OVPN $FP_SETTINGS_DIETPI $FP_CLIENT_OVPN

		# Apply credentials to client config
		G_CONFIG_INJECT 'auth-user-pass([[:blank:]]|$)' "auth-user-pass $FP_SETTINGS_OVPN" $FP_CLIENT_OVPN

		# Apply static up/down scripts to client config
		G_CONFIG_INJECT 'script-security[[:blank:]]' 'script-security 2' $FP_CLIENT_OVPN 'auth[[:blank:]]'
		G_CONFIG_INJECT 'up[[:blank:]]' "up $FP_STATIC_UP" $FP_CLIENT_OVPN 'script-security[[:blank:]]'
		G_CONFIG_INJECT 'down[[:blank:]]' "down $FP_STATIC_DOWN" $FP_CLIENT_OVPN 'up[[:blank:]]'

		# Apply or remove custom up/down scripts from client config
		# shellcheck disable=SC2015
		[[ -f $FP_CUSTOM_UP ]] && G_CONFIG_INJECT 'route-up[[:blank:]]' "route-up $FP_CUSTOM_UP" $FP_CLIENT_OVPN 'up[[:blank:]]' || G_EXEC sed -i '/^[[:blank:]]*route-up[[:blank:]]/d' $FP_CLIENT_OVPN
		# shellcheck disable=SC2015
		[[ -f $FP_CUSTOM_DOWN ]] && G_CONFIG_INJECT 'route-pre-down[[:blank:]]' "route-pre-down $FP_CUSTOM_DOWN" $FP_CLIENT_OVPN 'down[[:blank:]]' || G_EXEC sed -i '/^[[:blank:]]*route-pre-down[[:blank:]]/d' $FP_CLIENT_OVPN

		# Establish and test connection
		G_EXEC systemctl restart dietpi-vpn
		local i=1
		until Check_Connected || (( $i > $CONNECTION_TIMEOUT ))
		do
			G_DIETPI-NOTIFY -2 "Waiting for connection ($((i++))/$CONNECTION_TIMEOUT)"
			sleep 1
		done

		if (( $VPN_CONNECTED ))
		then
			G_DIETPI-NOTIFY 0 "Connection established: $VPN_SERVER"
		else
			G_DIETPI-NOTIFY 1 "Connection failed/timeout: $VPN_SERVER"
			G_EXEC systemctl stop dietpi-vpn
			G_WHIP_MSG "Connection failed/timeout: $VPN_SERVER\n\nPlease verify account details are correct.\n\nIf problems persist, please check the service status: \"systemctl -l status dietpi-vpn\""
		fi
	}

	#/////////////////////////////////////////////////////////////////////////////////////
	# Menus
	#/////////////////////////////////////////////////////////////////////////////////////
	TARGETMENUID=0
	LAST_SELECTED_NAME='Username'

	Menu_Provider()
	{
		G_WHIP_MENU_ARRAY=(

			'NordVPN' ': Connect to NordVPN'
			'ProtonVPN' ': Connect to ProtonVPN'
			'IPVanish' ': Connect to IPVanish'
			'PIA' ': Connect to Private Internet Access'
			'Custom' ': Use your own .ovpn file'
		)
		G_WHIP_DEFAULT_ITEM=$VPN_PROVIDER
		G_WHIP_MENU 'Please choose your VPN provider:' || return 1
		local provider=$G_WHIP_RETURNED_VALUE
		VPN_PROVIDER=$provider Update_Servers || return 1
		VPN_PROVIDER=$provider
	}

	Menu_Exit(){ G_WHIP_SIZE_X_MAX=50 G_WHIP_YESNO "Exit $G_PROGRAM_NAME?" && TARGETMENUID=-1; }

	# TARGETMENUID=0
	Menu_Main()
	{
		# Obtain connection status
		local text_status="WAN IP       : $WAN_IP\nState        : "
		if ! Check_Connected
		then
			text_status+='Disconnected'
			[[ $VPN_PROVIDER == 'NordVPN' ]] && text_status+='\nNordVPN Subscription : https://go.nordvpn.net/aff_c?offer_id=15&aff_id=5305&url_id=902'
		else
			Get_Connection_Info
			text_status+="Connected\nTraffic      : Sent = $TX | Received = $RX"
		fi

		# Obtain connection settings
		local autostart_enabled=0 autostart_text='Off'
		systemctl -q is-enabled dietpi-vpn && { autostart_enabled=1 autostart_text='On'; }
		local killswitch_enabled=0 killswitch_text='Off'
		[[ -f $FP_SETTINGS/killswitch.rules ]] && { killswitch_enabled=1 killswitch_text='On'; }

		G_WHIP_MENU_ARRAY=(

			'' '●─ Connection Settings '
			'Provider' ": [$VPN_PROVIDER]"
			'Username' ": [$VPN_USERNAME]"
			'Password' ": [${VPN_PASSWORD//?/*}]"
		)
		[[ $VPN_PROVIDER == 'Custom' ]] || G_WHIP_MENU_ARRAY+=('Server' ": [$VPN_SERVER]")
		G_WHIP_MENU_ARRAY+=('' '●─ Control Options ')
		(( $VPN_CONNECTED )) && G_WHIP_MENU_ARRAY+=('Disconnect' '')
		G_WHIP_MENU_ARRAY+=('Refresh' ': Update VPN connection status')
		[[ $VPN_PROVIDER == 'Custom' ]] || G_WHIP_MENU_ARRAY+=('Update' ': Update VPN server list')
		G_WHIP_MENU_ARRAY+=(

			'Reset' ': Remove and reset ALL configs and settings'
			'' '●─ Advanced Options '
			'Autostart' ": [$autostart_text]"
			'Killswitch' ": [$killswitch_text]"
			'Edit Up' ': This script gets executed right after the VPN is connected'
			'Edit Down' ': This script gets executed right before the VPN is disconnected'
			'' '●─ Save Settings '
			'Apply' ': Save settings and restart VPN connection'
		)

		G_WHIP_DEFAULT_ITEM=$LAST_SELECTED_NAME
		G_WHIP_BUTTON_CANCEL_TEXT='Exit'
		if G_WHIP_MENU "$text_status"
		then
			LAST_SELECTED_NAME=$G_WHIP_RETURNED_VALUE

			if [[ $G_WHIP_RETURNED_VALUE == 'Apply' ]]
			then
				Save_Settings
				Update_WAN_IP

			elif [[ $G_WHIP_RETURNED_VALUE == 'Edit'* ]]
			then
				local fp=$FP_CUSTOM_UP
				[[ $G_WHIP_RETURNED_VALUE == *'Down' ]] && fp=$FP_CUSTOM_DOWN
				[[ -f $fp ]] || echo -e '#!/bin/bash\n# Clear this file completely, including line breaks, to have it removed.' > $fp
				nano $fp
				if [[ -s $fp ]]
				then
					G_EXEC_NOEXIT=1 G_EXEC chmod 0700 $fp
				else
					G_EXEC_NOEXIT=1 G_EXEC rm $fp
				fi

			elif [[ $G_WHIP_RETURNED_VALUE == 'Autostart' ]]
			then
				if (( $autostart_enabled ))
				then
					G_EXEC_NOEXIT=1 G_EXEC systemctl disable dietpi-vpn
				else
					G_EXEC_NOEXIT=1 G_EXEC systemctl enable dietpi-vpn
				fi

			elif [[ $G_WHIP_RETURNED_VALUE == 'Killswitch' ]]
			then
				if (( $killswitch_enabled ))
				then
					G_EXEC rm $FP_SETTINGS/killswitch.rules
				else
					G_AG_CHECK_INSTALL_PREREQ iptables
					cat << '_EOF_' > $FP_SETTINGS/killswitch.rules
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
-A OUTPUT -o lo -j ACCEPT
-A OUTPUT -o tun0 -j ACCEPT
-A OUTPUT -d 192.168.0.0/16 -j ACCEPT
-A OUTPUT -d 172.16.0.0/12 -j ACCEPT
-A OUTPUT -d 10.0.0.0/8 -j ACCEPT
-A OUTPUT -d $VPN_SERVER -p $PROTOCOL --dport $VPN_PORT -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp --dport 22 -j ACCEPT
COMMIT
_EOF_
				fi

			elif [[ $G_WHIP_RETURNED_VALUE == 'Provider' ]]
			then
				Menu_Provider

			elif [[ $G_WHIP_RETURNED_VALUE == 'Username' ]]
			then
				G_WHIP_DEFAULT_ITEM=$VPN_USERNAME
				G_WHIP_INPUTBOX 'Please enter your VPN account username:\n\nNB: For ProtonVPN, use the OpenVPN credentials located at https://account.protonvpn.com/account' && VPN_USERNAME=$G_WHIP_RETURNED_VALUE

			elif [[ $G_WHIP_RETURNED_VALUE == 'Password' ]]
			then
				G_WHIP_PASSWORD 'Please enter your VPN account password:\n\nNB: For ProtonVPN, use the OpenVPN credentials located at https://account.protonvpn.com/account' && VPN_PASSWORD=$result
				unset -v result

			elif [[ $G_WHIP_RETURNED_VALUE == 'Disconnect' ]]
			then
				G_EXEC systemctl stop dietpi-vpn
				Update_WAN_IP
				LAST_SELECTED_NAME='Refresh'

			elif [[ $G_WHIP_RETURNED_VALUE == 'Server' ]]
			then
				# Select protocol
				G_WHIP_MENU_ARRAY=(

					'UDP' ': Recommended'
					'TCP' ': Reliable'
				)

				G_WHIP_DEFAULT_ITEM=${PROTOCOL^^}
				G_WHIP_MENU 'Please select the connection protocol type:' && PROTOCOL=${G_WHIP_RETURNED_VALUE,,}

				# Select server
				G_DIETPI-NOTIFY 2 'Populating VPN server list, please wait...'
				G_WHIP_MENU_ARRAY=()
				if [[ $VPN_PROVIDER == 'NordVPN' ]]
				then
					for i in "$FP_NORDVPN/ovpn_$PROTOCOL/"*.ovpn
					do
						G_WHIP_MENU_ARRAY+=("${i##*/}" '')
					done

				elif [[ $VPN_PROVIDER == 'ProtonVPN' ]]
				then
					# Get the list of server names from the file
					while read -r server
					do
						G_WHIP_MENU_ARRAY+=("$server" '')

					done < "$FP_PROTONVPN_SERVERS"

				elif [[ $VPN_PROVIDER == 'IPVanish' ]]
				then
					for i in "$FP_IPVANISH/"*.ovpn
					do
						G_WHIP_MENU_ARRAY+=("${i##*/}" '')
					done

				elif [[ $VPN_PROVIDER == 'PIA' ]]
				then
					for i in "$FP_PIA/"*.ovpn
					do
						G_WHIP_MENU_ARRAY+=("${i##*/}" '')
					done
				fi
				G_WHIP_DEFAULT_ITEM=$VPN_SERVER
				G_WHIP_MENU 'Please select a VPN server to use:' && VPN_SERVER=$G_WHIP_RETURNED_VALUE

			elif [[ $G_WHIP_RETURNED_VALUE == 'Refresh' ]]
			then
				Update_WAN_IP

			elif [[ $G_WHIP_RETURNED_VALUE == 'Update' ]]
			then
				Update_Servers -f

			elif [[ $G_WHIP_RETURNED_VALUE == 'Reset' ]]
			then
				G_WHIP_YESNO 'WARNING: This will turn off DietPi-VPN and will remove all configuration files.\n\nIf you want to use DietPi-VPN in the future, you will have to go through the setup again.'
				G_EXEC systemctl disable --now dietpi-vpn
				G_EXEC rm -Rf $FP_CLIENT_OVPN $FP_SETTINGS $FP_NORDVPN $FP_PROTONVPN $FP_IPVANISH $FP_PIA
				# Offer to purge OpenVPN, if neither OpenVPN (server) nor PiVPN is installed
				! grep -qE '^[[:blank:]]*aSOFTWARE_INSTALL_STATE\[(9|11)7\]=2' /boot/dietpi/.installed && G_WHIP_YESNO 'Do you want to have the underlying OpenVPN package removed as well?' && G_AGP openvpn
				exit 0
			fi
		else
			Menu_Exit
		fi
	}

	#/////////////////////////////////////////////////////////////////////////////////////
	# Main Loop
	#/////////////////////////////////////////////////////////////////////////////////////
	#-----------------------------------------------------------------------------------
	if [[ $INPUT == 'status' ]]
	then
		if [[ ! -f $FP_CLIENT_OVPN ]]
		then
			echo -e "\e[33m$G_PROGRAM_NAME is not configured! Please run: \"dietpi-vpn\"\e[0m"

		elif ! Check_Connected
		then
			echo -e '\e[1;31mDisconnected\e[0m'
		else
			Get_Connection_Info
			echo -e "\e[1;32mConnected\e[0m - Sent = $TX | Received = $RX"
		fi

	elif [[ $INPUT ]]
	then
		# Unknown input
		echo -e "\e[90m[\e[0m\e[31mFAILURE\e[0m\e[90m]\e[0m \e[90m$G_PROGRAM_NAME | \e[0mInvalid input command ($INPUT). Aborting...\n$USAGE"
		exit 1
	else
		G_AG_CHECK_INSTALL_PREREQ openvpn
		Read_Settings
		[[ -d $FP_SETTINGS ]] || G_EXEC mkdir -p $FP_SETTINGS
		[[ $VPN_PROVIDER ]] || Menu_Provider || exit 0
		Update_WAN_IP

		until (( $TARGETMENUID < 0 ))
		do
			Menu_Main
		done
	fi
	#-----------------------------------------------------------------------------------
	exit
	#-----------------------------------------------------------------------------------
}
